#ifndef __MY_DATA__
#define __MY_DATA__
#include <unordered_map>
#include <pthread.h>
#include "util.hpp"
#include "config.hpp"

namespace cloud
{
	// 一个结构体BackupInfo 里包含各种文件信息
	struct BackupInfo
	{
		bool pack_flag;
		size_t fsize;
		time_t mtime;
		time_t atime;
		std::string real_path; // 文件的实际存储路径名称
		std::string pack_path; // 文件的压缩包存储路径名称
		std::string url;

		// 创建(记录)一条新的备份相关信息 -- 因为怕丢
		bool NewBackupInfo(const std::string &realpath) // 输入型参数(外部会传进来一个realpath)
		{
			FileUtil fu(realpath);
			if (fu.Exists() == false)
			{
				std::cout << "new backupinfo: file not exists!\n";
				return false;
			}
			Config *config = Config::GetInstance(); // 获取config 可以根据config得到更多的信息
			std::string packdir = config->GetPackDir();
			std::string packsuffix = config->GetPackFileSuffix();
			std::string download_prefix = config->GetDownloadPrefix();

			pack_flag = false; // 有新的备份相关信息 就说明之前是没有备份的 所以备份标志位==false
			fsize = fu.FileSize();
			mtime = fu.LastMTime();
			atime = fu.LastATime();
			real_path = realpath;
			// ./backdir/a.txt   ->   ./packdir/a.txt.lz
			pack_path = packdir + fu.FileName() + packsuffix; ///// 压缩包路径+文件名+压缩后缀
			// ./backdir/a.txt   ->	  /download/a.txt
			url = download_prefix + fu.FileName(); //////////////// 下载前缀+文件名称
			return true;
		}
	};

	///////////////

	class DataManager
	{
	private:
		std::string _backup_file;
		pthread_rwlock_t _rwlock;
		std::unordered_map<std::string, BackupInfo> _table;

	public:
		DataManager()
		{
			_backup_file = Config::GetInstance()->GetBackupFile();
			pthread_rwlock_init(&_rwlock, NULL); // 初始化读写锁
			InitLoad();
		}
		~DataManager()
		{
			pthread_rwlock_destroy(&_rwlock); // 销毁读写锁
		}

		bool Insert(const BackupInfo &info)
		{
			pthread_rwlock_wrlock(&_rwlock);
			_table[info.url] = info;
			pthread_rwlock_unlock(&_rwlock);
			Storage();
			return true;
		}
		bool Update(const BackupInfo &info)
		{
			pthread_rwlock_wrlock(&_rwlock);
			_table[info.url] = info;
			pthread_rwlock_unlock(&_rwlock);
			Storage();
			return true;
		}
		bool GetOneByURL(const std::string &url, BackupInfo *info)
		{
			pthread_rwlock_wrlock(&_rwlock);
			// 因为url是key值，所以直接通过find进行查找    value是数据信息info
			auto it = _table.find(url);
			if (it == _table.end())
			{
				pthread_rwlock_unlock(&_rwlock);
				return false;
			}
			*info = it->second;
			pthread_rwlock_unlock(&_rwlock);
			return true;
		}
		bool GetOneByRealPath(const std::string &realpath, BackupInfo *info)
		{
			pthread_rwlock_wrlock(&_rwlock);
			auto it = _table.begin();
			for (; it != _table.end(); ++it)
			{
				if (it->second.real_path == realpath)
				{
					*info = it->second;
					pthread_rwlock_unlock(&_rwlock);
					return true;
				}
			}
			pthread_rwlock_unlock(&_rwlock);
			return false;
		}
		bool GetAll(std::vector<BackupInfo> *array) // 把table(unordered_map)中的value(BackupInfo)push_back到array中
		{
			pthread_rwlock_wrlock(&_rwlock);
			auto it = _table.begin();
			for (; it != _table.end(); ++it)
			{
				array->push_back(it->second);
			}
			pthread_rwlock_unlock(&_rwlock);
			return true;
		}

		// 持久化存储-改完保存
		bool Storage()
		{
			// 1. 获取(读取)所有数据
			std::vector<BackupInfo> array; // 所有数据在数组中保存着
			GetAll(&array);
			// 2. 添加到Json::Value
			Json::Value root;
			for (int i = 0; i < array.size(); i++)
			{
				Json::Value item;
				item["pack_flag"] = array[i].pack_flag;
				item["fsize"] = (Json::Int64)array[i].fsize;
				item["atime"] = (Json::Int64)array[i].atime;
				item["mtime"] = (Json::Int64)array[i].mtime;
				item["real_path"] = array[i].real_path;
				item["pack_path"] = array[i].pack_path;
				item["url"] = array[i].url;
				root.append(item); // 添加数组元素
			}
			// 3. 对Json::Value序列化
			std::string body;
			JsonUtil::Serialize(root, &body);
			// 4. 写文件
			FileUtil fu(_backup_file);
			fu.SetContent(body);
			return true;
		}

		// 初始化加载功能--每次重新启动都要加载以前的数据
		bool InitLoad()
		{
			// 1. 将数据文件中的数据读取出来
			FileUtil fu(_backup_file);
			if (fu.Exists() == false)
			{
				return true;
			}
			std::string body;
			fu.GetContent(&body);
			// 2. 反序列化
			Json::Value root;
			JsonUtil::UnSerialize(body, &root);
			// 3. 将反序列化得到的Json::Value中的数据添加(加载)到table中
			for (int i = 0; i < root.size(); i++)
			{
				BackupInfo info;
				info.pack_flag = root[i]["pack_flag"].asBool();
				info.fsize = root[i]["fsize"].asInt64();
				info.atime = root[i]["atime"].asInt64();
				info.mtime = root[i]["mtime"].asInt64();
				info.pack_path = root[i]["pack_path"].asString();
				info.real_path = root[i]["real_path"].asString();
				info.url = root[i]["url"].asString();
				Insert(info);
			}
			return true;
		}
	};
}

#endif
